Add GtkBoolFilter
authorBenjamin Otte <otte@redhat.com>
Sun, 26 Jul 2020 15:55:54 +0000 (17:55 +0200)
committerBenjamin Otte <otte@redhat.com>
Sun, 26 Jul 2020 18:43:08 +0000 (20:43 +0200)
Takes a boolean GtkExpression (like a boolean object property) to run a
filter with.

docs/reference/gtk/gtk4-docs.xml
docs/reference/gtk/gtk4-sections.txt
gtk/gtk.h
gtk/gtkboolfilter.c [new file with mode: 0644]
gtk/gtkboolfilter.h [new file with mode: 0644]
gtk/meson.build
testsuite/gtk/filter.c

index 8a10fe490801fbe0e5df6752472fb033da22d676..37b22c4d8022e05bc6837bae8aaa9818fd475435 100644 (file)
@@ -55,6 +55,7 @@
         <xi:include href="xml/gtkfilter.xml" />
         <xi:include href="xml/gtkcustomfilter.xml" />
         <xi:include href="xml/gtkmultifilter.xml" />
+        <xi:include href="xml/gtkboolfilter.xml" />
         <xi:include href="xml/gtkstringfilter.xml" />
         <xi:include href="xml/gtkfilefilter.xml" />
       </section>
index 2881f94dbe0a4d88eaa4b836348ad683da8f284f..5026765ca3558049d9e53ca45cb1509b0c9e97ba 100644 (file)
@@ -7571,6 +7571,19 @@ GTK_TYPE_EXPRESSION
 gtk_expression_get_type
 </SECTION>
 
+<SECTION>
+<FILE>gtkboolfilter</FILE>
+GtkBoolFilter
+gtk_bool_filter_new
+gtk_bool_filter_get_expression
+gtk_bool_filter_set_expression
+gtk_bool_filter_get_invert
+gtk_bool_filter_set_invert
+
+<SUBSECTION Private>
+gtk_bool_filter_get_type
+</SECTION>
+
 <SECTION>
 <FILE>gtkstringfilter</FILE>
 GtkStringFilter
index 50c23caf264e748a786e47c016e7c2dd2f7169f8..2277e1136d531de55af4c4931c1bb20e6543ea3f 100644 (file)
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -49,6 +49,7 @@
 #include <gtk/gtkbinlayout.h>
 #include <gtk/gtkbitset.h>
 #include <gtk/gtkbookmarklist.h>
+#include <gtk/gtkboolfilter.h>
 #include <gtk/gtkborder.h>
 #include <gtk/gtkboxlayout.h>
 #include <gtk/gtkbox.h>
diff --git a/gtk/gtkboolfilter.c b/gtk/gtkboolfilter.c
new file mode 100644 (file)
index 0000000..9a5ac17
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * Copyright © 2020 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+#include "config.h"
+
+#include "gtkboolfilter.h"
+
+#include "gtkintl.h"
+#include "gtktypebuiltins.h"
+
+/**
+ * SECTION:gtkboolfilter
+ * @Title: GtkBoolFilter
+ * @Short_description: Filtering by boolean expressions
+ *
+ * GtkBoolFilter is a simple filter that takes a boolean #GtkExpression
+ * to determine whether to include items.
+ */
+
+struct _GtkBoolFilter
+{
+  GtkFilter parent_instance;
+
+  gboolean invert;
+  GtkExpression *expression;
+};
+
+enum {
+  PROP_0,
+  PROP_EXPRESSION,
+  PROP_INVERT,
+  NUM_PROPERTIES
+};
+
+G_DEFINE_TYPE (GtkBoolFilter, gtk_bool_filter, GTK_TYPE_FILTER)
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
+
+static gboolean
+gtk_bool_filter_match (GtkFilter *filter,
+                       gpointer   item)
+{
+  GtkBoolFilter *self = GTK_BOOL_FILTER (filter);
+  GValue value = G_VALUE_INIT;
+  gboolean result;
+
+  if (self->expression == NULL ||
+      !gtk_expression_evaluate (self->expression, item, &value))
+    return FALSE;
+  result = g_value_get_boolean (&value);
+
+  g_value_unset (&value);
+
+  if (self->invert)
+    result = !result;
+
+  return result;
+}
+
+static GtkFilterMatch
+gtk_bool_filter_get_strictness (GtkFilter *filter)
+{
+  GtkBoolFilter *self = GTK_BOOL_FILTER (filter);
+
+  if (self->expression == NULL)
+    return GTK_FILTER_MATCH_NONE;
+
+  return GTK_FILTER_MATCH_SOME;
+}
+
+static void
+gtk_bool_filter_set_property (GObject      *object,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+  GtkBoolFilter *self = GTK_BOOL_FILTER (object);
+
+  switch (prop_id)
+    {
+    case PROP_EXPRESSION:
+      gtk_bool_filter_set_expression (self, gtk_value_get_expression (value));
+      break;
+
+    case PROP_INVERT:
+      gtk_bool_filter_set_invert (self, g_value_get_boolean (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void 
+gtk_bool_filter_get_property (GObject     *object,
+                              guint        prop_id,
+                              GValue      *value,
+                              GParamSpec  *pspec)
+{
+  GtkBoolFilter *self = GTK_BOOL_FILTER (object);
+
+  switch (prop_id)
+    {
+    case PROP_EXPRESSION:
+      gtk_value_set_expression (value, self->expression);
+      break;
+
+    case PROP_INVERT:
+      g_value_set_boolean (value, self->invert);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_bool_filter_dispose (GObject *object)
+{
+  GtkBoolFilter *self = GTK_BOOL_FILTER (object);
+
+  g_clear_pointer (&self->expression, gtk_expression_unref);
+
+  G_OBJECT_CLASS (gtk_bool_filter_parent_class)->dispose (object);
+}
+
+static void
+gtk_bool_filter_class_init (GtkBoolFilterClass *class)
+{
+  GtkFilterClass *filter_class = GTK_FILTER_CLASS (class);
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  filter_class->match = gtk_bool_filter_match;
+  filter_class->get_strictness = gtk_bool_filter_get_strictness;
+
+  object_class->get_property = gtk_bool_filter_get_property;
+  object_class->set_property = gtk_bool_filter_set_property;
+  object_class->dispose = gtk_bool_filter_dispose;
+
+  /**
+   * GtkBoolFilter:expression: (type GtkExpression)
+   *
+   * The boolean expression to evalute on item
+   */
+  properties[PROP_EXPRESSION] =
+    gtk_param_spec_expression ("expression",
+                               P_("Expression"),
+                               P_("Expression to evaluate"),
+                               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+  /**
+   * GtkBoolFilter:invert:
+   *
+   * If the expression result should be inverted
+   */
+  properties[PROP_INVERT] =
+      g_param_spec_boolean ("invert",
+                            P_("Invert"),
+                            P_("If the expression result should be inverted"),
+                            FALSE,
+                            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+  g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
+}
+
+static void
+gtk_bool_filter_init (GtkBoolFilter *self)
+{
+}
+
+/**
+ * gtk_bool_filter_new:
+ * @expression: (transfer full) (nullable): The expression to evaluate
+ *     or %NULL for none
+ *
+ * Creates a new bool filter.
+ *
+ * Returns: a new #GtkBoolFilter
+ **/
+GtkFilter *
+gtk_bool_filter_new (GtkExpression *expression)
+{
+  GtkFilter *result;
+
+  result = g_object_new (GTK_TYPE_BOOL_FILTER,
+                         "expression", expression,
+                         NULL);
+
+  g_clear_pointer (&expression, gtk_expression_unref);
+
+  return result;
+}
+
+/**
+ * gtk_bool_filter_get_expression:
+ * @self: a #GtkBoolFilter
+ *
+ * Gets the expression that the filter uses to evaluate if
+ * an item should be filtered.
+ *
+ * Returns: (transfer none): a #GtkExpression
+ */
+GtkExpression *
+gtk_bool_filter_get_expression (GtkBoolFilter *self)
+{
+  g_return_val_if_fail (GTK_IS_BOOL_FILTER (self), NULL);
+
+  return self->expression;
+}
+
+/**
+ * gtk_bool_filter_set_expression:
+ * @self: a #GtkBoolFilter
+ * @expression: a #GtkExpression
+ *
+ * Sets the expression that the filter uses to
+ * check if items should be filtered. The expression must have
+ * a value type of #G_TYPE_BOOLEAN.
+ */
+void
+gtk_bool_filter_set_expression (GtkBoolFilter *self,
+                                GtkExpression *expression)
+{
+  g_return_if_fail (GTK_IS_BOOL_FILTER (self));
+  g_return_if_fail (expression == NULL || gtk_expression_get_value_type (expression) == G_TYPE_BOOLEAN);
+
+  if (self->expression == expression)
+    return;
+
+  g_clear_pointer (&self->expression, gtk_expression_unref);
+  if (expression)
+    self->expression = gtk_expression_ref (expression);
+
+  gtk_filter_changed (GTK_FILTER (self), GTK_FILTER_CHANGE_DIFFERENT);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EXPRESSION]);
+}
+
+/**
+ * gtk_bool_filter_get_invert:
+ * @self: a #GtkBoolFilter
+ *
+ * Returns whether the filter inverts the expression.
+ *
+ * Returns: %TRUE if the filter inverts
+ */
+gboolean
+gtk_bool_filter_get_invert (GtkBoolFilter *self)
+{
+  g_return_val_if_fail (GTK_IS_BOOL_FILTER (self), TRUE);
+
+  return self->invert;
+}
+
+/**
+ * gtk_bool_filter_set_invert:
+ * @self: a #GtkBoolFilter
+ * @invert: %TRUE to invert
+ *
+ * Sets whether the filter should invert the expression.
+ */
+void
+gtk_bool_filter_set_invert (GtkBoolFilter *self,
+                            gboolean       invert)
+{
+  g_return_if_fail (GTK_IS_BOOL_FILTER (self));
+
+  if (self->invert == invert)
+    return;
+
+  self->invert = invert;
+
+  gtk_filter_changed (GTK_FILTER (self), GTK_FILTER_CHANGE_DIFFERENT);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INVERT]);
+}
+
diff --git a/gtk/gtkboolfilter.h b/gtk/gtkboolfilter.h
new file mode 100644 (file)
index 0000000..937f74a
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2020 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte@gnome.org>
+ */
+
+#ifndef __GTK_BOOL_FILTER_H__
+#define __GTK_BOOL_FILTER_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtkexpression.h>
+#include <gtk/gtkfilter.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_BOOL_FILTER             (gtk_bool_filter_get_type ())
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (GtkBoolFilter, gtk_bool_filter, GTK, BOOL_FILTER, GtkFilter)
+
+GDK_AVAILABLE_IN_ALL
+GtkFilter *             gtk_bool_filter_new                     (GtkExpression          *expression);
+
+GDK_AVAILABLE_IN_ALL
+GtkExpression *         gtk_bool_filter_get_expression          (GtkBoolFilter          *self);
+GDK_AVAILABLE_IN_ALL
+void                    gtk_bool_filter_set_expression          (GtkBoolFilter          *self,
+                                                                 GtkExpression          *expression);
+GDK_AVAILABLE_IN_ALL
+gboolean                gtk_bool_filter_get_invert              (GtkBoolFilter          *self);
+GDK_AVAILABLE_IN_ALL
+void                    gtk_bool_filter_set_invert              (GtkBoolFilter          *self,
+                                                                 gboolean                invert);
+
+
+G_END_DECLS
+
+#endif /* __GTK_BOOL_FILTER_H__ */
index a30f2e9d8932ca276568de0182956e07d05893df..2e681354223eb6e78c4748895fafffc8e8e3a1a9 100644 (file)
@@ -27,6 +27,7 @@ gtk_private_sources = files([
   'gtkbookmarksmanager.c',
   'gtkbuilder-menus.c',
   'gtkbuilderprecompile.c',
+  'gtkbuiltinicon.c',
   'gtkcellareaboxcontext.c',
   'gtkcoloreditor.c',
   'gtkcolorplane.c',
@@ -108,7 +109,6 @@ gtk_private_sources = files([
   'gtkgizmo.c',
   'gtkgladecatalog.c',
   'gtkhsla.c',
-  'gtkbuiltinicon.c',
   'gtkiconcache.c',
   'tools/gtkiconcachevalidator.c',
   'gtkiconhelper.c',
@@ -164,6 +164,7 @@ gtk_public_sources = files([
   'gtkassistant.c',
   'gtkbinlayout.c',
   'gtkbitset.c',
+  'gtkboolfilter.c',
   'gtkbookmarklist.c',
   'gtkborder.c',
   'gtkboxlayout.c',
@@ -452,6 +453,7 @@ gtk_public_headers = files([
   'gtkbinlayout.h',
   'gtkbitset.h',
   'gtkbookmarklist.h',
+  'gtkboolfilter.h',
   'gtkborder.h',
   'gtkbox.h',
   'gtkboxlayout.h',
index 22498bf20caf7354b6c1e07785cfa44d1af30bbf..76636cc1dfddb23056e1bbecc34750a6a2ebdeff 100644 (file)
@@ -309,6 +309,50 @@ test_string_properties (void)
   g_object_unref (filter);
 }
 
+static void
+test_bool_simple (void)
+{
+  GtkFilterListModel *model;
+  GtkExpression *expr;
+  GtkFilter *filter;
+
+  filter = gtk_bool_filter_new (
+               gtk_cclosure_expression_new (G_TYPE_BOOLEAN,
+                                            NULL,
+                                            0, NULL,
+                                            G_CALLBACK (divisible_by),
+                                            GUINT_TO_POINTER (3), NULL));
+  model = new_model (20, filter);
+  assert_model (model, "3 6 9 12 15 18");
+
+  gtk_bool_filter_set_invert (GTK_BOOL_FILTER (filter), TRUE);
+  assert_model (model, "1 2 4 5 7 8 10 11 13 14 16 17 19 20");
+
+  gtk_bool_filter_set_invert (GTK_BOOL_FILTER (filter), FALSE);
+  assert_model (model, "3 6 9 12 15 18");
+
+  expr = gtk_cclosure_expression_new (G_TYPE_BOOLEAN,
+                                      NULL,
+                                      0, NULL,
+                                      G_CALLBACK (divisible_by),
+                                      GUINT_TO_POINTER (5), NULL);
+  gtk_bool_filter_set_expression (GTK_BOOL_FILTER (filter), expr);
+  gtk_expression_unref (expr);
+  assert_model (model, "5 10 15 20");
+
+  gtk_bool_filter_set_invert (GTK_BOOL_FILTER (filter), TRUE);
+  assert_model (model, "1 2 3 4 6 7 8 9 11 12 13 14 16 17 18 19");
+
+  gtk_bool_filter_set_expression (GTK_BOOL_FILTER (filter), NULL);
+  assert_model (model, "");
+
+  gtk_bool_filter_set_invert (GTK_BOOL_FILTER (filter), FALSE);
+  assert_model (model, "");
+
+  g_object_unref (filter);
+  g_object_unref (model);
+}
+
 static void
 test_every_dispose (void)
 {
@@ -343,6 +387,7 @@ main (int argc, char *argv[])
   g_test_add_func ("/filter/any/simple", test_any_simple);
   g_test_add_func ("/filter/string/simple", test_string_simple);
   g_test_add_func ("/filter/string/properties", test_string_properties);
+  g_test_add_func ("/filter/bool/simple", test_bool_simple);
   g_test_add_func ("/filter/every/dispose", test_every_dispose);
 
   return g_test_run ();